#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

// 文件信息结构体
typedef struct FileInfo {
    char name[256];       // 文件名
    char path[1024];      // 文件路径
    off_t size;           // 文件大小
    time_t modify_time;   // 最后修改时间(时间戳)
} FileInfo;

// 二叉树节点结构体
typedef struct TreeNode {
    FileInfo data;
    struct TreeNode* left;  // 左子树
    struct TreeNode* right; // 右子树
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(const FileInfo* fileInfo) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode == NULL) {
        perror("malloc failed");
        return NULL;
    }
    
    // 复制文件信息到节点
    strncpy(newNode->data.name, fileInfo->name, sizeof(newNode->data.name) - 1);
    strncpy(newNode->data.path, fileInfo->path, sizeof(newNode->data.path) - 1);
    newNode->data.size = fileInfo->size;
    newNode->data.modify_time = fileInfo->modify_time;
    
    newNode->left = NULL;
    newNode->right = NULL;
    
    return newNode;
}

// 插入节点到二叉搜索树（按文件名排序）
TreeNode* insertNode(TreeNode* root, const FileInfo* fileInfo) {
    if (root == NULL) {
        return createNode(fileInfo);
    }
    
    // 按文件名比较，决定插入左子树还是右子树
    int cmp = strcmp(fileInfo->name, root->data.name);
    if (cmp < 0) {
        root->left = insertNode(root->left, fileInfo);
    } else if (cmp > 0) {
        root->right = insertNode(root->right, fileInfo);
    } else {
        // 文件名相同，这里简单处理为不插入，可以根据需求修改
        printf("警告: 已存在同名文件 %s,未重复索引\n", fileInfo->name);
    }
    
    return root;
}

// 搜索文件
TreeNode* searchFile(TreeNode* root, const char* fileName) {
    if (root == NULL) {
        return NULL;
    }
    
    int cmp = strcmp(fileName, root->data.name);
    if (cmp == 0) {
        return root;  // 找到文件
    } else if (cmp < 0) {
        return searchFile(root->left, fileName);  // 在左子树中搜索
    } else {
        return searchFile(root->right, fileName); // 在右子树中搜索
    }
}

// 中序遍历（按文件名升序输出）
void inOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    
    inOrderTraversal(root->left);
    
    // 格式化输出文件信息
    struct tm* timeinfo = localtime(&root->data.modify_time);
    char timeStr[20];
    strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M", timeinfo);
    
    printf("文件名: %s\n", root->data.name);
    printf("路径: %s\n", root->data.path);
    printf("大小: %ld 字节\n", root->data.size);
    printf("修改时间: %s\n", timeStr);
    printf("-------------------------\n");
    
    inOrderTraversal(root->right);
}

// 释放二叉树
void freeTree(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    
    freeTree(root->left);
    freeTree(root->right);
    free(root);
}

// 递归扫描目录并添加到二叉树
void scanDirectory(TreeNode** root, const char* dirPath) {
    DIR* dir = opendir(dirPath);
    if (dir == NULL) {
        perror("无法打开目录");
        return;
    }
    
    struct dirent* entry;
    while ((entry = readdir(dir)) != NULL) {
        // 跳过当前目录(.)和父目录(..)
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        
        // 构建新路径
        char newPath[1024];
        sprintf(newPath, "%s/%s", dirPath, entry->d_name);
        
        // 获取文件信息
        struct stat fileStat;
        if (stat(newPath, &fileStat) == -1) {
            perror("stst");
            continue;
        }
        
        // 如果是目录，递归扫描
        if (S_ISDIR(fileStat.st_mode)) {
            scanDirectory(root, newPath);
        } else if (S_ISREG(fileStat.st_mode)) {  
            // 如果是普通文件
            FileInfo fileInfo;
            strncpy(fileInfo.name, entry->d_name, sizeof(fileInfo.name) - 1);
            strncpy(fileInfo.path, newPath, sizeof(fileInfo.path) - 1);
            fileInfo.size = fileStat.st_size;
            fileInfo.modify_time = fileStat.st_mtime;
            
            // 插入到二叉树
            *root = insertNode(*root, &fileInfo);
        }
    }
    
    closedir(dir);
}

// 打印文件信息
void printFileInfo(const FileInfo* fileInfo) {
    if (fileInfo == NULL) {
        printf("文件不存在\n");
        return;
    }
    
    //将时间戳类型转换为本地时间格式
    struct tm* timeinfo = localtime(&fileInfo->modify_time);
    char timeStr[20];
    strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", timeinfo);
    
    printf("找到文件:\n");
    printf("文件名: %s\n", fileInfo->name);
    printf("路径: %s\n", fileInfo->path);
    printf("大小: %ld 字节\n", fileInfo->size);
    printf("修改时间: %s\n", timeStr);
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        fprintf(stderr, "请正确使用,用法: %s + 目录路径\n", argv[0]);
        return 1;
    }
    
    // 检查目录是否存在
    if (access(argv[1], F_OK) == -1) {
        fprintf(stderr, "错误: 目录 %s 不存在\n", argv[1]);
        return 1;
    }
    
    TreeNode* root = NULL;
    
    printf("正在扫描目录: %s ...\n", argv[1]);
    scanDirectory(&root, argv[1]);
    printf("扫描完成，已索引文件\n");
    
    // 交互查询
    char input[256];
    while (1) {
        printf("\n请输入要查询的文件名(输入q或Q退出): ");
        if (fgets(input, sizeof(input), stdin) == NULL) {
            break;
        }
        
        // 去除输入文件名后按的回车键换行符
        input[strcspn(input, "\n")] = '\0';
        
        if (strcmp(input, "q") == 0 || strcmp(input, "Q") == 0) {
            break;
        }
        
        if (strlen(input) == 0) {
            continue;
        }
        
        // 搜索文件
        TreeNode* result = searchFile(root, input);
        printFileInfo(result ? &result->data : NULL);
    }
    
    // 释放资源
    freeTree(root);
    printf("程序已退出\n");
    
    return 0;
}
